using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Collections.Specialized;
using System.Configuration.Provider;
using System.IO;
using Commerce.Common;

namespace Commerce.Providers
{
    public class AuthorizeNetPaymentProvider:PaymentProvider
    {

        //properties
        #region Passed-in Props
        string serviceUserName = "";
        string servicePassword = "";
        string transactionKey = "";
        string serverURL = "";
        string currencyCode = "USD";
        #endregion

        #region Provider specific behaviors

        public override void Initialize(string name, NameValueCollection config)
        {

            // Verify that config isn't null
            if (config == null)
                throw new ArgumentNullException("config");
           
            // Assign the provider a default name if it doesn't have one
            if (String.IsNullOrEmpty(name))
            {
                config.Remove("name");
                config.Add("name",
                    "AuthorizeNetPaymentProvider");
            }            
            // Add a default "description" attribute to config if the
            // attribute doesn't exist or is empty
            if (string.IsNullOrEmpty(config["description"]))
            {
                config.Remove("description");
                config.Add("description",
                    "Authorize.Net Payment Provider");
            }
            base.Initialize(name, config);

            serviceUserName = config["serviceUserName"].ToString();
            if (String.IsNullOrEmpty(serviceUserName))
                throw new ProviderException("Empty Authorize.Net Username value");
            config.Remove("serviceUserName");

            servicePassword = config["servicePassword"].ToString();
            if (String.IsNullOrEmpty(servicePassword))
                throw new ProviderException("Empty Authorize.Net Password value");
            config.Remove("servicePassword");

            transactionKey = config["transactionKey"].ToString();
            if (String.IsNullOrEmpty(transactionKey))
                throw new ProviderException("Empty Transaction Key value");
            config.Remove("transactionKey");

            serverURL = config["serverURL"].ToString();
            if (String.IsNullOrEmpty(serverURL))
                throw new ProviderException("Empty Server URL value");
            config.Remove("serverURL");

            currencyCode = config["currencyCode"].ToString();
            if (String.IsNullOrEmpty(currencyCode))
                throw new ProviderException("Empty Currency Code value");
            config.Remove("currencyCode");

        
        }

        public override string Name
        {
            get
            {
                return null;
            }
        }
        #endregion

        public override Commerce.Common.Transaction Charge(Commerce.Common.Order order)
        {
            //string sOut = "";

            decimal dTotal = order.OrderTotal;
            int roundTo = System.Globalization.CultureInfo.CurrentCulture.NumberFormat.CurrencyDecimalDigits;
            dTotal = Math.Round(dTotal, roundTo);

            //make sure that the ExpMonth has a leading 0
            string sExpMonth = order.CreditCardExpireMonth.ToString();
            if (order.CreditCardExpireMonth < 10)
                sExpMonth = "0" + sExpMonth;

            bool useTestServer = serverURL.IndexOf("test") >= 0;


            String result = "";
            String strPost = "x_login=" + serviceUserName +
                "&x_tran_key=" + transactionKey +
                "&x_method=CC" +
                "&x_type=AUTH_CAPTURE" +
                "&x_amount=" + dTotal.ToString() +
                "&x_delim_data=TRUE" +
                "&x_delim_char=|" +
                "&x_relay_response=FALSE" +
                "&x_card_num=" + order.CreditCardNumber +
                "&x_exp_date=" + sExpMonth + order.CreditCardExpireYear.ToString() +
                "&x_version=3.1" +
                //the following is optional however it's good to have for records
                "&x_first_name=" + order.BillingAddress.FirstName +
                "&x_last_name=" + order.BillingAddress.LastName +
                "&x_address=" + order.BillingAddress.Address1 +
                "&x_city=" + order.BillingAddress.City +
                "&x_state=" + order.BillingAddress.StateOrRegion +
                "&x_zip=" + order.BillingAddress.Zip +
                "&x_currency_code=" + currencyCode +
                "&x_country=" + order.BillingAddress.Country +
                "&x_card_code=" + order.CreditCardSecurityNumber +
                "&x_invoice_num=" + order.OrderNumber;

            //you can set this up to send you an email if you like
            //by adding this: 
            //&x_merchant_email=me@email.com

            //you can also have them send you customer an email
            //&x_email=mycustomer@email.com&x_email_customer=TRUE


            if (useTestServer)
                strPost += "&x_test_request=TRUE";

            StreamWriter myWriter = null;

            HttpWebRequest objRequest = (HttpWebRequest)WebRequest.Create(serverURL);
            objRequest.Method = "POST";
            objRequest.ContentLength = strPost.Length;
            objRequest.ContentType = "application/x-www-form-urlencoded";

            try
            {
                myWriter = new StreamWriter(objRequest.GetRequestStream());
                myWriter.Write(strPost);
            }
            catch (Exception e)
            {
                throw e;
            }
            finally
            {
                myWriter.Close();
            }
            Commerce.Common.Transaction trans = new Commerce.Common.Transaction();

            HttpWebResponse objResponse = (HttpWebResponse)objRequest.GetResponse();

            using (StreamReader reader = new StreamReader(objResponse.GetResponseStream()))
            {
                result = reader.ReadToEnd();

                // the result is a pipe-delimited set
                // parse this out so we know what happened
                string[] lines = result.Split('|');

                // the response flag is the first item
                // 1=success, 2=declined, 3=error, 4=held
                string responseCode = lines[0];

                // string transactionID = "";
                // string authCode = "";
                string reason = lines[3];

                switch (responseCode)
                {
                    case "1":
                        //trans.GatewayResponse = lines[37];
                        trans.AuthorizationCode = lines[4];

                        // return the transactionID
                        trans.GatewayResponse = result;
                        break;
                    case "2":
                        trans.GatewayResponse = lines[2];
                        throw new Exception("Declined: " + reason);
                    case "3":
                        trans.GatewayResponse = lines[2];
                        throw new Exception("Error: " + result);
                    case "4":
                        trans.GatewayResponse = lines[3];
                        throw new Exception("Transaction held for review: " + result);
                    default:
                        trans.GatewayResponse = lines[3];
                        throw new Exception("Unknown response: " + result);
                }


                // Close and clean up the StreamReader
                reader.Close();
            }

            return trans;
        }

        public override string Refund(Order order)
        {
            throw new Exception("This method not enabled for Authorize.NET");
        }
    }
}
